package org.smartboot.pass;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smartboot.http.client.ResponseHandler;
import org.smartboot.http.client.impl.DefaultHttpResponseHandler;
import org.smartboot.http.client.impl.Response;
import org.smartboot.http.common.enums.HeaderNameEnum;
import org.smartboot.http.common.enums.HttpStatus;
import org.smartboot.http.common.utils.StringUtils;
import org.smartboot.http.server.HttpResponse;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

/**
 * @author 三刀（zhengjunweimail@163.com）
 * @version V1.0 , 2021/7/13
 */
public class RemoteHttpProxyResponseHandler extends ResponseHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(RemoteHttpProxyResponseHandler.class);
    /**
     * 客户端 response 对象
     */
    private final HttpResponse clientResponse;
    /**
     * 远程的 Http Body 明文响应
     */
    private ResponseHandler remoteResponseHandler;
    private int responseContentLength;

    public RemoteHttpProxyResponseHandler(HttpResponse clientResponse) {
        this.clientResponse = clientResponse;
    }

    @Override
    public void onHeaderComplete(Response proxyResponse) {
        if (proxyResponse.getStatus() == HttpStatus.PROXY_AUTHENTICATION_REQUIRED.value()) {
            clientResponse.setHttpStatus(HttpStatus.INTERNAL_SERVER_ERROR);
            try {
                clientResponse.getOutputStream().write("proxy server config error".getBytes(StandardCharsets.UTF_8));
            } catch (IOException e) {
                LOGGER.error("", e);
            }
            clientResponse.close();
            return;
        }
        responseContentLength = proxyResponse.getContentLength();

        clientResponse.setHttpStatus(proxyResponse.getStatus(), proxyResponse.getReasonPhrase());
        proxyResponse.getHeaderNames()
                .stream().filter(headerName -> !HeaderNameEnum.CONTENT_TYPE.getName().equalsIgnoreCase(headerName))
                .forEach(headerName -> clientResponse.setHeader(headerName, proxyResponse.getHeader(headerName)));
        clientResponse.setHeader(HeaderNameEnum.CONTENT_LENGTH.getName(), null);
        String contentType = proxyResponse.getContentType();
        if (StringUtils.isNotBlank(contentType)) {
            clientResponse.setHeader(HeaderNameEnum.CONTENT_TYPE.getName(), contentType);
        }
        clientResponse.setContentLength(proxyResponse.getContentLength());
        if (StringUtils.isNotBlank(proxyResponse.getContentType())) {
            clientResponse.setContentType(proxyResponse.getContentType());
        }
        clientResponse.setCharacterEncoding(proxyResponse.getCharacterEncoding());
        try {
            clientResponse.getOutputStream().flush();
        } catch (IOException e) {
            LOGGER.error("", e);
        }
        remoteResponseHandler = new DefaultHttpResponseHandler();
    }

    @Override
    public boolean onBodyStream(ByteBuffer buffer, Response proxyResponse) {
        int pos = buffer.position();
        try {
            if (responseContentLength > 0) {
                int readSize = Math.min(responseContentLength, buffer.remaining());
                buffer.position(pos + readSize);
                responseContentLength -= readSize;
                return responseContentLength == 0;
            } else {
                return remoteResponseHandler.onBodyStream(buffer, proxyResponse);
            }
        } finally {
            try {
                clientResponse.getOutputStream().directWrite(buffer.array(), pos + buffer.arrayOffset(), buffer.position() - pos);
                clientResponse.getOutputStream().flush();
            } catch (IOException e) {
                LOGGER.error("", e);
            }
        }
    }
}
